﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Interop;
using System.Windows;
using PlayNugetPackage.TCPHelper;

namespace WpfApp1
{
    public class PSocket
    {
        public IPSocket? Open(string ip = "127.0.0.1", int port = 1234, bool isClient = true)
        {
            IPSocket socket = new P_Server();
            if (isClient)
            {
                socket = new P_Client();
            }
            var temp = socket.OpenConnected(ip, port);
            if (temp == null)
            {
                return null;
            }
            return socket;
        }
        //public IPlaySocket? Open(string ip = "127.0.0.1", int port = 1234, bool isClient = true)
        //{
        //    IPlaySocket socket = new PlayNugetPackage.TCPHelper.PlayTCPServer();
        //    if (isClient)
        //    {
        //        socket = new PlayTCPClient();
        //    }
        //    var temp = socket.OpenConnected(ip, port);
        //    if (temp == null)
        //    {
        //        return null;
        //    }
        //    return socket;
        //}
    }

    public interface IPSocket
    {
        /// <summary>
        /// 打开连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns>返回的是打开的对象</returns>
        Socket? OpenConnected(string ip, int port);
        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <returns></returns>
        bool CloseConnected();
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="targetClient">服务端发送指定客户端则设置客户端socket，否则不填</param>
        void SendData(string msg, Socket? targetClient = null);
        /// <summary>
        /// 数据接受事件
        /// </summary>

        event Action<Socket,object>? OnReceviceData;
        /// <summary>
        /// 断开连接事件
        /// </summary>

        event Action<Socket?>? OnDisconnected;
        /// <summary>
        /// 获取当前socket对象
        /// </summary>
        /// <returns></returns>

        Socket? GetSocket();

    }
    public class P_Server : IPSocket
    {
        bool isDoClosed = false;//关闭操作标识
        bool isConnected = false;//是否打开了连接
        Socket? _mySocket;//当前的socket对象
        List<Socket> clinetList=new List<Socket>();//客户端集合
        /// <summary>
        /// 客户端断开事件
        /// </summary>
        public event Action<Socket>? OnClinetConnected;
        public event Action<Socket,object>? OnReceviceData;

        public event Action<Socket>? OnDisconnected;

        public bool CloseConnected()
        {
            isDoClosed = true;
            if (_mySocket == null)
            {
                return true;
            }
            try
            {
                // 关闭监听Socket
                _mySocket.Close();
                //_mySocket.Dispose();
                // 关闭所有客户端连接
                lock (clinetList)
                {
                    foreach (var clientSocket in clinetList)
                    {
                        clientSocket.Shutdown(SocketShutdown.Both);
                        clientSocket.Close();
                    }
                    clinetList.Clear();
                }
                isConnected = false;
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
            finally
            {
                
            }
        }
        /// <summary>
        /// 返回所有连接的客户端
        /// </summary>
        /// <returns></returns>
        public List<Socket> GetClinetList()
        {
            return clinetList;
        }
        /// <summary>
        /// 返回当前服务端的socket实例
        /// </summary>
        /// <returns></returns>
        public Socket? GetSocket()
        {
            return _mySocket;
        }
        /// <summary>
        /// 是否打开连接
        /// </summary>
        /// <returns></returns>
        public bool IsConnected()
        {
            return isConnected;
        }
        /// <summary>
        /// 打开服务端监听
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public Socket? OpenConnected(string ip, int port)
        {
            if (isConnected)
            {
                return _mySocket;
            }
            var ipAndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
            var mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                mySocket.Bind(ipAndPoint);
                mySocket.Listen(10);
                Task.Run(() =>
                {
                    while (true)
                    {
                        try
                        {
                            //判断是否关闭了服务端，关闭了不在执行循环接收客户端连接
                            if (mySocket.Connected == false && isDoClosed)
                            {
                                isDoClosed = false;
                                return;
                            }
                            // 接受客户端连接
                            Socket clientSocket = mySocket.Accept();

                            // 处理客户端连接
                            ReceiveDataFromClient(clientSocket);
                            // 客户端连接事件
                            OnClinetConnected?.Invoke(clientSocket);
                            clinetList.Add(clientSocket);
                        }
                        catch (SocketException ex)
                        {

                            if (ex.ErrorCode == 10004)//一个封锁操作被对 WSACancelBlockingCall 的调用中断。
                            {

                            }
                            else
                            {
                                throw new Exception(ex.Message);
                            }
                        }


                    }
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return null;
            }
            
            isConnected = true;
            _mySocket = mySocket;
            return _mySocket;
        }

        public void SendData(string msg,Socket? targetClient=null)
        {
            if(targetClient == null)
            {
                return;
            }
            try
            {
                byte[] bytStr = Encoding.Default.GetBytes(msg);
                targetClient.Send(bytStr);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message.ToString());
            }
        }

        /// <summary>
        /// 处理客户端连接
        /// </summary>
        /// <param name="rcvSocket">客户端连接</param>
        void ReceiveDataFromClient(Socket rcvSocket)
        {
            Task.Run(() =>
            {
                using (rcvSocket)
                {
                    while (true)
                    {
                        byte[] byt = new byte[2];
                        try
                        {
                            int len = rcvSocket.Receive(byt,  SocketFlags.None);//byt为接收到的字符数组
                            if (rcvSocket.Poll(0, SelectMode.SelectRead) == false&&len==0)//判断客户端是否断开了连接
                            {
                                if (rcvSocket.Connected == true)
                                {
                                    clinetList.Remove(rcvSocket);
                                    OnDisconnected?.Invoke(rcvSocket);
                                }
                                
                                break;
                            }
                            //数据转换
                            var data = Encoding.Default.GetString(byt, 0, len);
                            while (rcvSocket.Available!=0)
                            {
                                len = rcvSocket.Receive(byt, SocketFlags.None);//byt为接收到的字符数组
                                data += Encoding.Default.GetString(byt, 0, len);
                            }
                            OnReceviceData?.Invoke(rcvSocket,data);
                            
                        }
                        catch(SocketException ex)
                        {
                            if(ex.ErrorCode== 10054)//"远程主机强迫关闭了一个现有的连接。"
                            {
                                clinetList.Remove(rcvSocket);
                                OnDisconnected?.Invoke(rcvSocket);
                                return;
                            }  
                            else if (ex.ErrorCode == 10053)//你的主机中的软件中止了一个已建立的连接。
                            {
                                //OnClinetDisconnected?.Invoke(rcvSocket);
                                return;
                            }
                            else
                            {
                                throw new Exception(ex.Message);
                            }
                        }
                        
                    }
                }
            });
        }
    }

    public class P_Client : IPSocket
    {
        bool isConnected = false;
        Socket? _mySocket;
        public event Action<Socket,object>? OnReceviceData;

        public event Action<Socket?>? OnDisconnected;

        public bool CloseConnected()
        {
            if (_mySocket == null)
            {
                return true;
            }
            try
            {
                _mySocket.Close();
                _mySocket.Dispose();
                isConnected = false;
                return true;
            }
            catch (Exception )
            {
                return false;
            }
        }

        public bool IsConnected()
        {
            return isConnected;
        }

        public Socket? OpenConnected(string ip, int port)
        {
            if (isConnected)
                return _mySocket;
            var ipAndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
            var mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                mySocket.Connect(ipAndPoint);
                ReceiveDataFromServer(mySocket);
                isConnected = true;
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.Message);
                mySocket = null;
                isConnected = false;
            }
            _mySocket=mySocket;
            return mySocket;
        }
        /// <summary>
        /// 客户端数据接收处理
        /// </summary>
        /// <param name="rcvSocket"></param>
        /// <exception cref="Exception"></exception>
        void ReceiveDataFromServer(Socket rcvSocket)
        {
            Task.Run(() =>
            {
                using (rcvSocket)
                {
                    while (true)
                    {
                        byte[] byt = new byte[2];
                        try
                        {
                            int len = rcvSocket.Receive(byt, SocketFlags.None);
                            //判断连接是否断开
                            if (rcvSocket.Poll(3000, SelectMode.SelectRead))
                            {
                                if (rcvSocket.Available == 0)
                                {
                                    OnDisconnected?.Invoke(null);
                                    isConnected = false;
                                    _mySocket = null;
                                    return;
                                }
                                
                            }
                            //数据转换
                            var data = Encoding.Default.GetString(byt, 0, len);
                            while (rcvSocket.Available != 0)
                            {
                                len = rcvSocket.Receive(byt, SocketFlags.None);//byt为接收到的字符数组
                                data += Encoding.Default.GetString(byt, 0, len);
                            }
                            OnReceviceData?.Invoke(rcvSocket, data);
                        }
                        catch (SocketException ex)
                        {
                            if (ex.ErrorCode == 10054)
                            {
                                return;
                            }
                            else if (ex.ErrorCode == 10053)//你的主机中的软件中止了一个已建立的连接。
                            {
                                return;
                            }
                            else
                            {
                                throw new Exception(ex.Message);
                            }
                        }
                        if(rcvSocket.Connected) { }
                    }
                }
            });

        }
        public void SendData(string msg, Socket? targetClient = null)
        {
            if (_mySocket == null)
                return;
            if(_mySocket.Connected == false)//如果服务端关闭了会把客户端也关闭，也就是这里的_mySocket将被释放无法使用
            {
                return;
            }
            try
            {
                if (_mySocket.RemoteEndPoint == null)
                {
                    return;
                }
                byte[] bytStr = Encoding.Default.GetBytes(msg);

                _mySocket.Send(bytStr);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message.ToString());
            }
        }
        public Socket? GetSocket()
        {
            return _mySocket;
        }
    }
}